﻿// Decompiled with JetBrains decompiler
// Type: Netick.NetworkPlayer
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Collections.Generic;
using System.Numerics;

#nullable disable
namespace Netick;

/// <summary>
/// Represents a network player, which can be either a local player (representing this player) or a remote connection (representing a connected client)).
/// </summary>
public abstract class NetworkPlayer
{
  public readonly NetickEngine Engine;
  internal readonly List<Entity> ControlledEntities;
  private Vector3 _position;
  private Vector3 _viewDirection;
  private float _distance = 1000f;
  private float _fieldOfViewAngle = 90f;
  internal int Index = -1;

  internal Vector3 Position
  {
    get => this._position;
    set
    {
      this._position = value;
      if (!this.Engine.IsClient || this.Engine.IsResimulating || !this.Engine.Tick.IsValid)
        return;
      this.Engine._cliSim._clientReplicatorDataBuffer[this.Engine.Tick % this.Engine._cliSim._clientReplicatorDataBuffer.Length].Position = value;
    }
  }

  internal Vector3 ViewDirection
  {
    get => this._viewDirection;
    set
    {
      this._viewDirection = value;
      if (!this.Engine.IsClient || this.Engine.IsResimulating || !this.Engine.Tick.IsValid)
        return;
      this.Engine._cliSim._clientReplicatorDataBuffer[this.Engine.Tick % this.Engine._cliSim._clientReplicatorDataBuffer.Length].ViewDirection = value;
    }
  }

  internal float Distance
  {
    get => this._distance;
    set
    {
      this._distance = value;
      if (!this.Engine.IsClient || this.Engine.IsResimulating || !this.Engine.Tick.IsValid)
        return;
      this.Engine._cliSim._clientReplicatorDataBuffer[this.Engine.Tick % this.Engine._cliSim._clientReplicatorDataBuffer.Length].Distance = value;
    }
  }

  internal float FieldOfViewAngle
  {
    get => this._fieldOfViewAngle;
    set
    {
      this._fieldOfViewAngle = value;
      if (!this.Engine.IsClient || this.Engine.IsResimulating || !this.Engine.Tick.IsValid)
        return;
      this.Engine._cliSim._clientReplicatorDataBuffer[this.Engine.Tick % this.Engine._cliSim._clientReplicatorDataBuffer.Length].FieldOfViewAngle = value;
    }
  }

  /// <summary>
  /// The networked index of this player.
  /// <para>Note: it returns -1 on the client for the local player when not connected to a server.</para>
  /// <para>Note: the server player always has Id 0.</para>
  /// </summary>
  public NetworkPlayerId PlayerId
  {
    get
    {
      return this.Engine.IsClient ? (this == this.Engine.LocalPlayer ? (this.Engine._cliSim.LocalInputSourceIndex != -1 ? NetworkPlayerId.Create(this.Engine._cliSim.LocalInputSourceIndex + 1) : new NetworkPlayerId()) : (this == this.Engine.Client.ConnectedServer ? NetworkPlayerId.Create(0) : NetworkPlayerId.Create(this.Engine._cliSim.LocalInputSourceIndex + 1))) : (this.Engine.LocalPeer == this ? NetworkPlayerId.Create(0) : NetworkPlayerId.Create(this.Index + 1));
    }
  }

  /// <summary>
  /// Use this to associate an object with this player. This is a local variable that is not synced.
  /// </summary>
  [Obsolete("This will be removed in the future.")]
  public object PlayerObject { get; set; }

  internal NetworkPlayer(NetickEngine engine)
  {
    this.Engine = engine;
    this.ControlledEntities = new List<Entity>(128 /*0x80*/);
  }

  internal virtual void Reset() => this.PlayerObject = (object) null;

  public void AddInterestGroup(int groupId)
  {
    if (groupId < 0 || groupId >= this.Engine._IM.CustomGroups.Length)
      NetickLogger.LogError(this.Engine, (object) $"{groupId} group Id is incorrect.");
    else
      this.AddInterestGroup(this.Engine._IM.CustomGroups[groupId]);
  }

  public void AddInterestGroup(InterestManagementGroup group)
  {
    if (!(this is ServerConnection serverConnection))
      return;
    int index = serverConnection.Index;
    if (group.Clients[index])
      return;
    group.Clients[index] = true;
    serverConnection._interestGroups.Add(group);
  }

  public void AddInterestBoxArea(NetickBounds box, int layerIndex = 0)
  {
    if (layerIndex > this.Engine._config.AoILayerCount - 1)
    {
      NetickLogger.LogError(this.Engine, (object) $"AoI layer index [{layerIndex}] is out of bounds.");
    }
    else
    {
      if (!(this is ServerConnection serverConnection))
        return;
      serverConnection.AoIQueries.Add(new AoIQuery()
      {
        Layer = layerIndex,
        IsBox = true,
        Bounds = box
      });
    }
  }

  internal void ReleaseControlledEntities()
  {
    for (int index = this.ControlledEntities.Count - 1; index >= 0; --index)
      this.ControlledEntities[index].InvokeOnInputSourceLeft();
    for (int index = this.ControlledEntities.Count - 1; index >= 0; --index)
      this.ControlledEntities[index].InvokeOnInputSourceChanged(this);
    for (int index = this.ControlledEntities.Count - 1; index >= 0; --index)
      this.ControlledEntities[index].SetInputSourceAsNull();
    this.ControlledEntities.Clear();
  }

  internal unsafe bool IsThisInputSourceOfEntity(Entity entity)
  {
    return this.Engine._entityMetaReplicator.GetEntityMeta(entity.WorldIndex)->InputSourceId == (this.Engine.IsServer ? -2 : this.Engine._cliSim.LocalInputSourceIndex);
  }

  public override string ToString() => this.PlayerId.ToString();
}
